package org.xiaowu.wpywebframework.core.utils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import org.springframework.scheduling.support.CronExpression;

/**
 * 时间工具类（企业规范版，增强版）
 * 
 * 功能覆盖：
 *  - 当前时间获取
 *  - 格式化与解析
 *  - 时区转换
 *  - 时间加减与计算
 *  - 时间比较与区间判断
 *  - 时间差计算
 *  - 日期范围生成
 *  - 时间戳转换
 *  - Cron 表达式下一次执行时间
 *  - 人性化时间显示（几分钟前、几天前）
 *
 * 线程安全、无副作用、零依赖。
 */
public class DateTimeUtils {

    /** 默认时区（东八区） */
    private static final ZoneId DEFAULT_ZONE = ZoneId.of("Asia/Shanghai");

    /** 常用时间格式 */
    public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_PATTERN = "yyyy-MM-dd";
    public static final String TIME_PATTERN = "HH:mm:ss";
    public static final String DATETIME_COMPACT_PATTERN = "yyyyMMddHHmmss";

    private DateTimeUtils() {}

    /* ========================= 当前时间 ========================= */

    public static LocalDateTime now() {
        return LocalDateTime.now(DEFAULT_ZONE);
    }

    public static LocalDate today() {
        return LocalDate.now(DEFAULT_ZONE);
    }

    public static long currentTimestamp() {
        return Instant.now().toEpochMilli();
    }

    public static Date nowDate() {
        return Date.from(Instant.now());
    }

    /* ========================= 格式化与解析 ========================= */

    public static String format(LocalDateTime time, String pattern) {
        if (time == null) return null;
        return time.format(DateTimeFormatter.ofPattern(pattern));
    }

    public static String format(LocalDate date, String pattern) {
        if (date == null) return null;
        return date.format(DateTimeFormatter.ofPattern(pattern));
    }

    public static LocalDateTime parseDateTime(String text, String pattern) {
        return LocalDateTime.parse(text, DateTimeFormatter.ofPattern(pattern));
    }

    public static LocalDate parseDate(String text, String pattern) {
        return LocalDate.parse(text, DateTimeFormatter.ofPattern(pattern));
    }

    /* ========================= Date 与 LocalDateTime 互转 ========================= */

    public static LocalDateTime toLocalDateTime(Date date) {
        if (date == null) return null;
        return LocalDateTime.ofInstant(date.toInstant(), DEFAULT_ZONE);
    }

    public static Date toDate(LocalDateTime localDateTime) {
        if (localDateTime == null) return null;
        return Date.from(localDateTime.atZone(DEFAULT_ZONE).toInstant());
    }

    public static Date toDate(LocalDate localDate) {
        if (localDate == null) return null;
        return Date.from(localDate.atStartOfDay(DEFAULT_ZONE).toInstant());
    }

    /* ========================= 时区转换 ========================= */

    public static LocalDateTime toUTC(LocalDateTime localDateTime) {
        if (localDateTime == null) return null;
        return localDateTime.atZone(DEFAULT_ZONE)
                .withZoneSameInstant(ZoneOffset.UTC)
                .toLocalDateTime();
    }

    public static LocalDateTime fromUTC(LocalDateTime utcTime) {
        if (utcTime == null) return null;
        return utcTime.atZone(ZoneOffset.UTC)
                .withZoneSameInstant(DEFAULT_ZONE)
                .toLocalDateTime();
    }

    /* ========================= 时间加减 ========================= */

    public static LocalDateTime addDays(LocalDateTime time, long days) {
        return time.plusDays(days);
    }

    public static LocalDateTime addHours(LocalDateTime time, long hours) {
        return time.plusHours(hours);
    }

    public static LocalDateTime addMinutes(LocalDateTime time, long minutes) {
        return time.plusMinutes(minutes);
    }

    public static LocalDateTime addSeconds(LocalDateTime time, long seconds) {
        return time.plusSeconds(seconds);
    }

    public static LocalDateTime addMonths(LocalDateTime time, long months) {
        return time.plusMonths(months);
    }

    public static LocalDateTime addYears(LocalDateTime time, long years) {
        return time.plusYears(years);
    }

    /* ========================= 时间比较 ========================= */

    public static boolean isBefore(LocalDateTime t1, LocalDateTime t2) {
        return t1.isBefore(t2);
    }

    public static boolean isAfter(LocalDateTime t1, LocalDateTime t2) {
        return t1.isAfter(t2);
    }

    public static boolean isEqual(LocalDateTime t1, LocalDateTime t2) {
        return t1.isEqual(t2);
    }

    public static boolean isBetween(LocalDateTime time, LocalDateTime start, LocalDateTime end) {
        return (time.isAfter(start) || time.isEqual(start))
                && (time.isBefore(end) || time.isEqual(end));
    }

    /* ========================= 时间差 ========================= */

    public static long diffDays(LocalDateTime start, LocalDateTime end) {
        return ChronoUnit.DAYS.between(start, end);
    }

    public static long diffHours(LocalDateTime start, LocalDateTime end) {
        return ChronoUnit.HOURS.between(start, end);
    }

    public static long diffMinutes(LocalDateTime start, LocalDateTime end) {
        return ChronoUnit.MINUTES.between(start, end);
    }

    public static long diffSeconds(LocalDateTime start, LocalDateTime end) {
        return ChronoUnit.SECONDS.between(start, end);
    }

    /* ========================= 日期范围 ========================= */

    public static List<LocalDate> getPastDays(int days) {
        List<LocalDate> list = new ArrayList<>();
        LocalDate today = today();
        for (int i = 0; i < days; i++) {
            list.add(today.minusDays(i));
        }
        Collections.reverse(list);
        return list;
    }

    public static List<LocalDate> getDatesOfMonth(int year, int month) {
        List<LocalDate> list = new ArrayList<>();
        YearMonth ym = YearMonth.of(year, month);
        for (int i = 1; i <= ym.lengthOfMonth(); i++) {
            list.add(LocalDate.of(year, month, i));
        }
        return list;
    }

    /* ========================= 时间戳 ========================= */

    public static long toTimestamp(LocalDateTime time) {
        return time.atZone(DEFAULT_ZONE).toInstant().toEpochMilli();
    }

    public static LocalDateTime fromTimestamp(long timestamp) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), DEFAULT_ZONE);
    }

    /* ========================= 其他 ========================= */

    public static boolean isSameDay(LocalDateTime t1, LocalDateTime t2) {
        return t1.toLocalDate().isEqual(t2.toLocalDate());
    }

    public static String nowFormatted() {
        return format(now(), DATETIME_PATTERN);
    }

    public static String todayFormatted() {
        return format(today(), DATE_PATTERN);
    }

    /* ========================= Cron 表达式 ========================= */

    /**
     * 获取 Cron 表达式的下一次执行时间
     * 
     * @param cronExpression Cron 表达式（例如："0 0/5 * * * ?"）
     * @return 下一次执行的 LocalDateTime（东八区）
     */
    public static LocalDateTime nextCronTime(String cronExpression) {
        CronExpression expression = CronExpression.parse(cronExpression);
        return expression.next(now());
    }

    /**
     * 获取未来 N 次执行时间
     */
    public static List<LocalDateTime> nextCronTimes(String cronExpression, int count) {
        List<LocalDateTime> times = new ArrayList<>();
        CronExpression expression = CronExpression.parse(cronExpression);
        LocalDateTime base = now();
        for (int i = 0; i < count; i++) {
            base = expression.next(base);
            if (base == null) break;
            times.add(base);
        }
        return times;
    }

    /* ========================= 人性化时间显示 ========================= */

    /**
     * 将时间转换成人性化描述，如：
     * - 刚刚
     * - 5分钟前
     * - 2小时前
     * - 昨天
     * - 3天前
     * - 一周前
     * - 一年前
     */
    public static String humanize(LocalDateTime time) {
        if (time == null) return "";
        long seconds = diffSeconds(time, now());
        if (seconds < 60) return "刚刚";
        long minutes = seconds / 60;
        if (minutes < 60) return minutes + "分钟前";
        long hours = minutes / 60;
        if (hours < 24) return hours + "小时前";
        long days = hours / 24;
        if (days == 1) return "昨天";
        if (days < 7) return days + "天前";
        if (days < 30) return (days / 7) + "周前";
        if (days < 365) return (days / 30) + "个月前";
        return (days / 365) + "年前";
    }
}
